#include "file_system.h"

uint8_t global_raw[PIECE_PAGE_SIZE] = {0x00};

File_System file_system = {
    .file_loader_init_bytes={'L', 'I', 'M', 0xBC, 0xFB, 0x40, 0x00, 0x00},
    .piece_start_init_bytes={0x00, 0x04, 0xFF, 0xFF},
    .max_pieces_num = (FLASH_MAX_SIZE * 1024 - LOADER_PAGE_SIZE - BITMAP_SIZE) / PIECE_PAGE_SIZE,
    .file_system_init = false,
    .file_system_state = CHECK_FILE_SYSTEM,
    .piece_info.find_avilable_piece = false,
    .piece_info.next_avilable_piece_id = 0xFFFF,
    .loader_info.loader_max_num = (LOADER_PAGE_SIZE - 10) / 5,
    .loader_info.next_loader_piece_id = 0xFFFF,
    .loader_info.flash_usage = 0,
    .loader_info.file_num = 0,
    .file_test.file_type = NORMAL_FILE,
    .file_test.start_create_file = false,
    .file_test.now_num = 0,
    .file_test.target_create_num = 0,
    .file_operate_test.open_if = false,
    .file_operate_test.operate_file.init_if = false,
    .file_operate_test.operate_file.file_state = CLOSE,
    .file_operate_test.find_way = BY_ID,
    .file_operate_test.tar_type = NORMAL_FILE,
    .file_operate_test.tar_file_id = 0,
    .file_operate_test.write_if = false,
		.file_operate_test.write_len = 0,
    .file_operate_test.write_buf = {
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9
            , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
    },
    .file_operate_test.close_if = false,
    .file_operate_test.read_if = false,
    .file_operate_test.read_start_at = 0,
		.file_operate_test.clear_if = false
};


void file_system_controller(void){
    switch (file_system.file_system_state)
    {
        case CHECK_FILE_SYSTEM:
            check_file_system();
            break;
        case FILE_SYSTEM_IDLE:
            file_system_idle();
            break;
        case FILE_SYSTEM_INIT:
						init_file_system();
            break;
        default:
            break;
    }
}

void file_system_idle(){
    if(file_system.file_system_init){
        file_system.file_system_state = FILE_SYSTEM_INIT;
        file_system.file_system_init = false;
    }
    else if (file_system.piece_info.find_avilable_piece){
        file_system.piece_info.next_avilable_piece_id = find_avilable_piece();
        file_system.piece_info.find_avilable_piece = false;
    }
    else if(file_system.file_test.start_create_file){
        if(file_system.file_test.now_num < file_system.file_test.target_create_num){
            create_file(file_system.file_test.file_type);
            file_system.file_test.now_num ++;
        }else{
            file_system.file_test.now_num = 0;
            file_system.file_test.start_create_file = false;
        }
    }
    else if(file_system.file_operate_test.open_if){
        file_system.file_operate_test.operate_file = open_file(file_system.file_operate_test.find_way, file_system.file_operate_test.tar_type, file_system.file_operate_test.tar_file_id);
        file_system.file_operate_test.open_if = false;
    }
    else if(file_system.file_operate_test.write_if){
        uint8_t cut_pieces = file_system.file_operate_test.write_len / 20 + 1;
        uint16_t write_left = file_system.file_operate_test.write_len;
        for(int i=0;i < cut_pieces; i++){
            uint8_t this_time_write_len = 0;
            if(write_left > 20){
                this_time_write_len = 20;
            }else{
                this_time_write_len = write_left;
            }
            file_write(&file_system.file_operate_test.operate_file, file_system.file_operate_test.write_buf, this_time_write_len);
            write_left -= this_time_write_len;
        }

        file_system.file_operate_test.write_if = false;
    }
    else if(file_system.file_operate_test.close_if){
        close_file(&file_system.file_operate_test.operate_file);
        file_system.file_operate_test.close_if = false;
    }
    else if(file_system.file_operate_test.read_if){
        file_read(&file_system.file_operate_test.operate_file, file_system.file_operate_test.read_buf, file_system.file_operate_test.read_start_at, 20);
        file_system.file_operate_test.read_if = false;
    }
    else if(file_system.file_operate_test.clear_if){
        clear_file(&file_system.file_operate_test.operate_file);
        file_system.file_operate_test.clear_if = false;
    }
}

void check_file_system(){
    if(flash_controller.flash_state == FLASH_IDLE){
        uint8_t loader_name[3];
        get_flash_data(&loader_name[0], 0, 3);
        if(memcmp(&loader_name[0],&file_system.file_loader_init_bytes[0], 3) == 0){
            file_system.piece_info.find_avilable_piece = true;
            file_system.file_system_state = FILE_SYSTEM_IDLE;
			update_loader_info();
        }
        else{
            file_system.file_system_state = FILE_SYSTEM_INIT;
        }
    }
}

void init_file_system(){
    clear_flash();
    if(check_busy()){
        
    }else{
		rewrite_flash(&file_system.file_loader_init_bytes[0], 0, 8);
        fill_data(0x00,LOADER_PAGE_SIZE, BITMAP_SIZE);
		file_system.file_system_state = CHECK_FILE_SYSTEM;
		reset_dart();
	}
}

uint32_t piece_id_to_addr(uint16_t piece_id){
    return LOADER_PAGE_SIZE + BITMAP_SIZE + piece_id * PIECE_PAGE_SIZE;
}

uint32_t addr_to_piece_id(uint32_t addr){
    if(addr < LOADER_PAGE_SIZE + BITMAP_SIZE){
        return 0xFFFF;
    }else{
        return (addr - LOADER_PAGE_SIZE - BITMAP_SIZE) /PIECE_PAGE_SIZE;
    }
}

uint16_t bitmap_offset_to_start_piece_id(uint16_t bitmap_offset){
    return bitmap_offset*2;
}

static uint16_t find_avilable_piece(void){
    uint16_t ret = 0xFFFF;
    for(int i=0;i< BITMAP_SIZE/MAX_READ_BUF; i++){
        get_flash_data(&flash_controller.read_buf[0], i*MAX_READ_BUF + BITMAP_SIZE, MAX_READ_BUF);
        int16_t useful_bitmap_index = find_avilable_bitmap_index(&flash_controller.read_buf[0], MAX_READ_BUF);
        uint8_t userful_bitmap_offset = 0;
        if(useful_bitmap_index != -1){
            userful_bitmap_offset = find_avilable_offset_of_bitmap_data(flash_controller.read_buf[useful_bitmap_index]);
            if(userful_bitmap_offset != 8){
                uint16_t avilable_ret = useful_bitmap_index * 8 + userful_bitmap_offset;
				ret = bitmap_offset_to_avilable_piece_id(avilable_ret);
                break;
            }else{
                break;
            }
        }else{
            break;
        }
    }
    return ret;
}

uint16_t bitmap_offset_to_avilable_piece_id(uint16_t bitmap_offset){
    Piece_memory_Info piece_memory_info;
    uint16_t piece_start_id = bitmap_offset_to_start_piece_id(bitmap_offset);
    for(int piece_id = piece_start_id; piece_id< piece_start_id + 2; piece_id++){
        piece_memory_info = get_piece_info(piece_id);
        if(piece_memory_info.piece_use == PIECE_IDLE){
            return piece_id;
        }
    }
    return 0xFFFF;
}

static uint8_t find_avilable_offset_of_bitmap_data(uint8_t bitmap_data){
    uint8_t ret = 0;
    for(ret = 0;ret < 8;ret ++){
        if((~bitmap_data >> ret) & 0x01){
            return ret;
        }
    }
    return 8;
}

static int16_t find_avilable_bitmap_index(uint8_t* bit_map_buf, uint16_t buf_len){
    int16_t ret = -1;
    for(int i=0;i< buf_len; i++){
        if(bit_map_buf[i] != 0xFF){
            ret = i;
            break;
        }
    }
    return ret;
}

uint8_t piece_id_get_bitmap_bit(uint16_t piece_id){
    uint16_t byte_offset = piece_id / 8;
    uint8_t bit_offset = piece_id - byte_offset * 8;
    uint8_t raw_data;
    get_flash_data(&raw_data, LOADER_PAGE_SIZE + byte_offset, 1);
    return (raw_data >> bit_offset) & 0x01;
}

uint8_t piece_id_get_bitmap_byte(uint16_t piece_id){
    uint16_t byte_offset = piece_id / 16;
    uint8_t raw_data;
    get_flash_data(&raw_data, LOADER_PAGE_SIZE + byte_offset, 1);
    return raw_data;
}

uint8_t check_bitmap_bit_usage(uint16_t piece_id){
    uint8_t use_count = 0;
    uint16_t another_piece_id = piece_id%2==0?piece_id+1:piece_id-1;
    Piece_memory_Info piece_memory_info = get_piece_info(another_piece_id);
    if(piece_memory_info.piece_use != PIECE_IDLE){
        use_count ++;
    }
    return use_count;
}

void set_bitmap_usage(uint16_t piece_id){
    uint8_t bit_usage = check_bitmap_bit_usage(piece_id);
    if(bit_usage == 1){
        uint8_t byte_get = piece_id_get_bitmap_byte(piece_id);
        uint16_t byte_offset = piece_id / 16;
        uint8_t bit_offset = (piece_id / 2) % 8;
        byte_get |= (1 << bit_offset) ;
        rewrite_flash(&byte_get, LOADER_PAGE_SIZE + byte_offset, 1);
    }
}

void clear_bitmap_usage(uint16_t piece_id){
    uint8_t byte_get = piece_id_get_bitmap_byte(piece_id);
    uint16_t byte_offset = piece_id / 16;
    uint8_t bit_offset = (piece_id / 2) % 8;
    byte_get &= ~(1 << bit_offset);
    rewrite_flash(&byte_get, LOADER_PAGE_SIZE + byte_offset, 1);
}

Piece_memory_Info get_piece_info(uint16_t piece_id){
    Piece_memory_Info piece_memory_info;
    uint8_t temp_buf[PIECE_PAGE_SIZE];
    get_flash_data(&temp_buf[0], piece_id_to_addr(piece_id), PIECE_PAGE_SIZE);
    piece_memory_info.piece_use = (Piece_Use)temp_buf[0];
    piece_memory_info.piece_usages = temp_buf[1];
    piece_memory_info.next_piece_id = (temp_buf[PIECE_PAGE_SIZE - 2] | (temp_buf[PIECE_PAGE_SIZE -1] << 8));
    return piece_memory_info;
}

void update_piece_next_piece_id(uint16_t now_piece_id, uint16_t new_piece_id){
    uint32_t piece_start_addr = piece_id_to_addr(now_piece_id);
    uint8_t write_buf[2] = {new_piece_id & 0xFF, (new_piece_id >> 8) & 0xFF};
    rewrite_flash(&write_buf[0], piece_start_addr + PIECE_PAGE_SIZE - 2, 2);
}

void update_loader_info(void){
    get_flash_data(&file_system.loader_info.raw_data[0], 3, 5);
    file_system.loader_info.flash_usage = (file_system.loader_info.raw_data[0] | (file_system.loader_info.raw_data[1] << 8) | (file_system.loader_info.raw_data[2] << 16));
    file_system.loader_info.file_num = (file_system.loader_info.raw_data[3] | (file_system.loader_info.raw_data[4] << 8));
    get_flash_data(&file_system.loader_info.raw_data[5], LOADER_PAGE_SIZE - 2, 2);
    file_system.loader_info.next_loader_piece_id = (file_system.loader_info.raw_data[5]) | (file_system.loader_info.raw_data[6] << 8); //error2
}


void init_piece_format(Piece_Use piece_use, uint16_t piece_id){
    uint32_t piece_addr_start = piece_id_to_addr(piece_id);
    uint8_t temp_operate_buf[PIECE_PAGE_SIZE];
    get_flash_data(&temp_operate_buf[0], piece_addr_start, PIECE_PAGE_SIZE);
    temp_operate_buf[0] = piece_use;
    temp_operate_buf[1] = file_system.piece_start_init_bytes[1];
    temp_operate_buf[PIECE_PAGE_SIZE - 2] = 0xFF;
    temp_operate_buf[PIECE_PAGE_SIZE - 1] = 0xFF;
    rewrite_flash(&temp_operate_buf[0], piece_addr_start, PIECE_PAGE_SIZE);
}


uint16_t flash_malloc_pieces(){
    uint16_t ret = find_avilable_piece();
    if(ret != 0xFFFF){
        set_bitmap_usage(ret);
    }
    return ret;
}

uint32_t get_lastest_loader_jump_addr(void){
    bool the_end = false;
    uint8_t raw_data[2];
    uint32_t now_loader_end_addr = LOADER_PAGE_SIZE - 2;
    while(!the_end){
        get_flash_data(&raw_data[0], now_loader_end_addr, 2);
        uint16_t now_piece_id = (raw_data[0] | (raw_data[1] << 8));
        if(now_piece_id == 0xFFFF){
            the_end = true;
        }
        else{
            now_loader_end_addr = piece_id_to_addr(now_piece_id) + PIECE_PAGE_SIZE - 2;
        }
    }
    return now_loader_end_addr;
}

uint16_t get_lastest_loader_piece_id(void){
    bool the_end = false;
    uint8_t raw_data[2];
    uint16_t ret_piece_id = 0xFFFF;
    uint16_t now_piece_id = 0xFFFF;
    uint32_t now_loader_end_addr = LOADER_PAGE_SIZE - 2;
    while(!the_end){
        get_flash_data(&raw_data[0], now_loader_end_addr, 2);
        ret_piece_id = now_piece_id;
        now_piece_id = (raw_data[0] | (raw_data[1] << 8));
        if(now_piece_id == 0xFFFF){
            the_end = true;
        }
        else{
            now_loader_end_addr = piece_id_to_addr(now_piece_id) + PIECE_PAGE_SIZE - 2;
        }
    }
    return ret_piece_id;
}

void extern_loader_area(){
    uint16_t piece_id = flash_malloc_pieces();
    if(piece_id != 0xFFFF){
        init_piece_format(PIECE_LOADER, piece_id);
        uint32_t last_loader_addr = get_lastest_loader_jump_addr();
        uint8_t raw_data[2] = {(piece_id & 0xFF), (piece_id >> 8) & 0xFF};
        rewrite_flash(&raw_data[0], last_loader_addr, 2);
    }
//    return piece_id;
}

uint32_t get_file_id_to_start_addr(uint16_t file_id){
    uint16_t lastest_piece_id = get_lastest_loader_piece_id();
    if(lastest_piece_id == 0xFFFF){
        if(8 + 5*(file_id + 1) > LOADER_PAGE_SIZE){
            extern_loader_area();
				}
        return 8 + 5 * file_id;
    }else{
        uint32_t ret_addr;
        uint32_t piece_addr = piece_id_to_addr(lastest_piece_id);
        Piece_memory_Info piece_memory_info = get_piece_info(lastest_piece_id);
        if(PIECE_PAGE_SIZE - piece_memory_info.piece_usages < 5){
            extern_loader_area();
            ret_addr = get_file_id_to_start_addr(file_id);
        }else{
            ret_addr = piece_addr + piece_memory_info.piece_usages - 2;
        }
        return ret_addr;
    }
}

void change_file_num(uint16_t file_num){
    uint8_t raw_data[2] = {file_num & 0xFF, (file_num >> 8) & 0xFF};
    rewrite_flash(&raw_data[0], 6, 2);
}

void add_file_to_loader(File_Type file_type, uint16_t file_id){
    uint32_t write_start_addr = get_file_id_to_start_addr(file_id);
    uint16_t file_start_piece_id = flash_malloc_pieces();
    if(file_start_piece_id != 0xFFFF){
        uint8_t raw_data[5];
        raw_data[0] = file_type;
        raw_data[1] = file_id & 0xFF;
        raw_data[2] = (file_id >> 8) & 0xFF;
        raw_data[3] = file_start_piece_id & 0xFF;
        raw_data[4] = (file_start_piece_id >> 8) & 0xFF;
        init_piece_format(PIECE_MEMORY, file_start_piece_id);
        file_system_mem_write(&raw_data[0], write_start_addr, 5, PIECE_LOADER);
    }
}

uint16_t create_file(File_Type file_type){
    update_loader_info();
    uint16_t new_file_id = file_system.loader_info.file_num;
    add_file_to_loader(file_type, new_file_id);
		update_loader_info();
    file_system.loader_info.file_num++;
    change_file_num(file_system.loader_info.file_num);
		file_system.piece_info.find_avilable_piece = true;
    return new_file_id;
}

uint32_t watch_buf[10];

void write_piece_data(uint8_t* write_buf, uint32_t start_addr, uint8_t write_len){
    uint16_t id_belong = addr_to_piece_id(start_addr);
    if(id_belong != 0xFFFF){
        get_flash_data(&global_raw[0], piece_id_to_addr(id_belong), 256);
//        Piece_memory_Info piece_mem_info = {
//                .next_piece_id = (read_buf[254] | read_buf[255] << 8),
//                .piece_usages = read_buf[1],
//                .piece_use = (Piece_Use)(read_buf[0])
//        };
        uint32_t id_st_addr = piece_id_to_addr(id_belong) + 2;
        memcpy(&global_raw[start_addr - id_st_addr + 2], &write_buf[0], write_len);
				if(start_addr - id_st_addr + write_len > global_raw[1] - 4){
					global_raw[1] = start_addr - id_st_addr + 2 + write_len + 2;
				}
        if(global_raw[1] == 0){
            global_raw[1] = 0xFF;
        }
        rewrite_flash(&global_raw[0], id_st_addr - 2, PIECE_PAGE_SIZE);
    }
}

uint32_t file_system_mem_write(uint8_t* data, uint32_t start_write_addr, uint32_t data_len, Piece_Use extern_as){
    uint32_t ret_addr = 0;
    if(data_len ==0){
        return ret_addr;
    }
    if(start_write_addr < LOADER_PAGE_SIZE){
        if(start_write_addr + data_len > LOADER_PAGE_SIZE){
            uint8_t cut_data_front_length = 5 - (start_write_addr + data_len - LOADER_PAGE_SIZE + 2);
            uint8_t cut_data_back_length = 5 - cut_data_front_length;
            uint8_t jump_piece_id[2];
            get_flash_data(&jump_piece_id[0], LOADER_PAGE_SIZE - 2, 2);
            uint16_t jump_to_piece = (jump_piece_id[0] | (jump_piece_id[1] << 8));
            rewrite_flash(&data[0], start_write_addr, cut_data_front_length);
            uint32_t next_write_addr = piece_id_to_addr(jump_to_piece) + 2;
            ret_addr = file_system_mem_write(&data[cut_data_front_length], next_write_addr, cut_data_back_length, extern_as);
        }else{
            rewrite_flash(&data[0], start_write_addr, data_len);
            ret_addr = start_write_addr + data_len;
        }
    }else{
        uint16_t piece_belong = addr_to_piece_id(start_write_addr);
        if(start_write_addr + data_len > piece_id_to_addr(piece_belong) + PIECE_PAGE_SIZE - 2){
            uint32_t this_piece_write_length = piece_id_to_addr(piece_belong) + PIECE_PAGE_SIZE - 2 - start_write_addr;  //error1
            uint32_t data_left = data_len - this_piece_write_length;
            write_piece_data(&data[0], start_write_addr, this_piece_write_length);
//            rewrite_flash(&data[0], start_write_addr, this_piece_write_length);
            Piece_memory_Info piece_mem_info = get_piece_info(piece_belong);
            if(piece_mem_info.next_piece_id == 0xFFFF){
                uint16_t new_piece_id = flash_malloc_pieces();
                if(new_piece_id != 0xFFFF){
                    init_piece_format(extern_as, new_piece_id);
                    update_piece_next_piece_id(piece_belong, new_piece_id);
                    ret_addr = file_system_mem_write(&data[this_piece_write_length], piece_id_to_addr(new_piece_id) + 2, data_left, extern_as);
                }
            }else{
                ret_addr = file_system_mem_write(&data[this_piece_write_length], piece_id_to_addr(piece_mem_info.next_piece_id), data_left, extern_as);
            }
        }else{
            write_piece_data(&data[0], start_write_addr, data_len);  // error 3
            ret_addr = start_write_addr + data_len;
        }
    }
    return ret_addr;
}

bool file_system_mem_read(uint8_t* read_buf, uint32_t start_read_addr,uint32_t start_offset, uint32_t read_len){
    bool ret = false;
    uint32_t new_addr_start = from_offset_to_new_start_addr(start_read_addr, start_offset);
    uint16_t id_belong = addr_to_piece_id(new_addr_start);
    Piece_memory_Info piece_mem_info = get_piece_info(id_belong);
    uint8_t this_piece_size_use = piece_mem_info.piece_usages - 3;
    uint8_t start_addr_in_piece_mem_offset = 252 - (piece_id_to_addr(id_belong) + PIECE_PAGE_SIZE - 2 - new_addr_start);
    if(start_addr_in_piece_mem_offset > this_piece_size_use){
        start_addr_in_piece_mem_offset = this_piece_size_use;
        ret = true;
    }
    uint8_t this_piece_data_left = this_piece_size_use - start_addr_in_piece_mem_offset;
    if(this_piece_data_left > read_len){
        get_flash_data(&read_buf[0], new_addr_start, read_len);
    }else{
        get_flash_data(&read_buf[0], new_addr_start, this_piece_data_left);
        if(piece_mem_info.next_piece_id != 0xFFFF){
            file_system_mem_read(&read_buf[this_piece_data_left], start_read_addr, start_offset + this_piece_data_left, read_len - this_piece_data_left);
        }
    }
    return ret;
}

void read_file_system_data(uint8_t* read_buf, uint32_t start_addr, uint32_t read_len){
//    uint8_t temp_buf[FILE_READ_BUF_LEN];
    if(start_addr < LOADER_PAGE_SIZE){
        if(start_addr + read_len < (LOADER_PAGE_SIZE - 2)){
            get_flash_data(&read_buf[0], start_addr, read_len);
        }else{
            uint32_t next_start_addr = piece_id_to_addr(file_system.loader_info.next_loader_piece_id) + 2;
            get_flash_data(&read_buf[0], start_addr, LOADER_PAGE_SIZE - start_addr - 2);
            read_file_system_data(&read_buf[LOADER_PAGE_SIZE - start_addr - 2], next_start_addr, read_len - (LOADER_PAGE_SIZE - start_addr));
        }
    }else{
        uint16_t piece_id_belong = addr_to_piece_id(start_addr);
        uint32_t this_piece_end_addr = piece_id_to_addr(piece_id_belong) + PIECE_PAGE_SIZE - 2;
        uint16_t size_left = this_piece_end_addr - start_addr;
        if(size_left > read_len){
            get_flash_data(&read_buf[0], start_addr, read_len);
        }else{
            Piece_memory_Info piece_mem_info = get_piece_info(piece_id_belong);
            uint32_t next_piece_addr = piece_id_to_addr(piece_mem_info.next_piece_id) + 2;
            get_flash_data(&read_buf[0], size_left, size_left);
            if(piece_mem_info.next_piece_id == 0xFFFF){
                return;
            }
            read_file_system_data(&read_buf[size_left], next_piece_addr, read_len - size_left);
        }
    }
}

uint32_t from_offset_to_new_start_addr(uint32_t start_addr, uint32_t offset){
    uint32_t ret = 0;
    if(start_addr < LOADER_PAGE_SIZE){
        if(start_addr + offset < (LOADER_PAGE_SIZE - 2)){
            ret = start_addr + offset;
        }else{
            if(file_system.loader_info.next_loader_piece_id == 0xFFFF){
                return 0;
            }
            uint32_t next_start_addr = piece_id_to_addr(file_system.loader_info.next_loader_piece_id) + 2;
            ret = from_offset_to_new_start_addr(next_start_addr, offset - (LOADER_PAGE_SIZE - 2 - start_addr));
        }
    }else{
        uint16_t piece_id_belong = addr_to_piece_id(start_addr);
        uint32_t this_piece_end_addr = piece_id_to_addr(piece_id_belong) + PIECE_PAGE_SIZE - 2;
        uint16_t size_left = this_piece_end_addr - start_addr;
        if(size_left > offset){
            ret = start_addr + offset;
        }else{
            Piece_memory_Info piece_mem_info = get_piece_info(piece_id_belong);
            uint32_t next_piece_addr = piece_id_to_addr(piece_mem_info.next_piece_id) + 2;
            if(piece_mem_info.next_piece_id == 0xFFFF){
                uint16_t new_piece_id = flash_malloc_pieces();
                if(new_piece_id != 0xFFFF){
                    init_piece_format(PIECE_MEMORY, new_piece_id);
                    update_piece_next_piece_id(piece_id_belong, new_piece_id);
                    ret = from_offset_to_new_start_addr(new_piece_id, offset - size_left);
                }else{
                    return 0xFFFF;
                }
            }
            ret = from_offset_to_new_start_addr(next_piece_addr, offset - size_left);
        }
    }
    return ret;
}

File_Loader_Info file_id_to_start_addr(uint16_t target_file_id){
    File_Loader_Info file_loader_info = {.start_piece_id = 0xFFFF};
    uint8_t raw_data[5];
    uint32_t file_read_offset = 5 * target_file_id;
    uint32_t addr_start = from_offset_to_new_start_addr(8, file_read_offset);
    if(addr_start == 0){
        return file_loader_info;
    }
		watch_buf[0] = addr_start;
    read_file_system_data(&raw_data[0], addr_start, 5);
    file_loader_info.file_id = target_file_id;
    file_loader_info.file_type = (File_Type)raw_data[0];
    file_loader_info.start_piece_id = (raw_data[3] | raw_data[4] << 8);
    return file_loader_info;
}

uint32_t get_file_end_ptr_offset(uint16_t start_piece_id){
    uint32_t offset_total = 0;
    uint32_t st_addr = piece_id_to_addr(start_piece_id);
    Piece_memory_Info piece_mem_info = get_piece_info(start_piece_id);
    offset_total = piece_mem_info.piece_usages - 4;
		if(piece_mem_info.next_piece_id != 0xFFFF){
			offset_total ++;
		}
    if(piece_mem_info.next_piece_id != 0xFFFF && piece_mem_info.next_piece_id != start_piece_id){
        offset_total += get_file_end_ptr_offset(piece_mem_info.next_piece_id);
    }
    return offset_total;
}

File_Struct open_file(Find_Way find_way, File_Type file_type, uint16_t file_id){
    File_Struct temp_file = {
            .init_if = false,
            .file_state = CLOSE,
            .file_ptr_offset = 0
    };
    update_loader_info();
    if(find_way == BY_ID){
        temp_file.file_loader_info = file_id_to_start_addr(file_id);
        if(temp_file.file_loader_info.start_piece_id != 0xFFFF){
            temp_file.file_ptr_offset = get_file_end_ptr_offset(temp_file.file_loader_info.start_piece_id);
            temp_file.file_state = OPEN;
            temp_file.init_if = true;
        }
    }else if(find_way == BY_BOTH){
				temp_file.file_loader_info = file_id_to_start_addr(file_id);
				if(temp_file.file_loader_info.start_piece_id != 0xFFFF && temp_file.file_loader_info.file_type == file_type){
            temp_file.file_ptr_offset = get_file_end_ptr_offset(temp_file.file_loader_info.start_piece_id);
            temp_file.file_state = OPEN;
            temp_file.init_if = true;
        }
		}
    return temp_file;
}

void file_write(File_Struct* file, uint8_t* write_data, uint32_t data_len){
    if(file->init_if && file->file_state == OPEN){
        file_system_mem_write(write_data, from_offset_to_new_start_addr(piece_id_to_addr(file->file_loader_info.start_piece_id) + 2, file->file_ptr_offset), data_len, PIECE_MEMORY);
        file->file_ptr_offset += data_len;
    }
}

void file_write_at(File_Struct* file, uint8_t* write_data, uint32_t data_len, uint32_t write_offset){
    if(file->init_if && file->file_state == OPEN){
        file_system_mem_write(write_data, from_offset_to_new_start_addr(piece_id_to_addr(file->file_loader_info.start_piece_id) + 2, write_offset), data_len, PIECE_MEMORY);
		}
		file->file_ptr_offset = get_file_end_ptr_offset(file->file_loader_info.start_piece_id);
}

void file_write_lines(File_Struct* file, uint8_t* write_data, uint32_t data_len){
//    uint8_t* new_data = (uint8_t*) F_MALLOC(data_len + 1);
//    memcpy(&new_data[0], &write_data[0], data_len);
//    new_data[data_len] = '\n';
		uint8_t endl = '\n';
    file_write(file, write_data, data_len);
		file_write(file, &endl, 1);
//    F_FREE(new_data);
}

bool file_read(File_Struct* file, uint8_t* read_buf, uint32_t read_start_at, uint32_t data_len){
    bool ret = false;
    if(file->init_if && file->file_state == OPEN){
        ret = file_system_mem_read(&read_buf[0], piece_id_to_addr(file->file_loader_info.start_piece_id) + 2, read_start_at, data_len);
    }
    return ret;
}

uint32_t file_read_piece(File_Struct* file, uint8_t* read_buf, uint16_t now_piece_id, uint8_t read_offset) {
    Piece_memory_Info piece_mem_info = get_piece_info(now_piece_id);
		if(read_offset > 252){
			read_offset = 252;
		}
		uint8_t now_read_size = 0;
		if(read_offset > piece_mem_info.piece_usages - 4){
			read_offset = piece_mem_info.piece_usages - 4;
		}
		now_read_size = piece_mem_info.piece_usages - 4 - read_offset;
		if(piece_mem_info.next_piece_id != 0xFFFF && now_read_size == 251){
			now_read_size ++;
		}
    get_flash_data(&read_buf[0], piece_id_to_addr(now_piece_id) + 2 + read_offset, now_read_size);
    return (piece_mem_info.next_piece_id) | ((now_read_size) << 16);
}

void close_file(File_Struct* file){
    file->file_state = CLOSE;
    file->init_if = false;
}

void clear_file(File_Struct* file){
    if(file->init_if && file->file_state == OPEN){
        uint16_t next_piece_id = 0x0000;
        uint16_t now_piece_id = file->file_loader_info.start_piece_id;
        while(next_piece_id != 0xFFFF){
            next_piece_id = get_piece_info(now_piece_id).next_piece_id;
            if(now_piece_id == file->file_loader_info.start_piece_id){
                init_piece_format(PIECE_MEMORY, now_piece_id);
            }else{
                init_piece_format(PIECE_IDLE, now_piece_id);
                clear_bitmap_usage(now_piece_id);
            }
            now_piece_id = next_piece_id;
        }
    }
}

void format_all_files(void){
    file_system.file_system_init = true;
}
